﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Netfraction
{
    /// <summary>
    /// Interaction logic for NICDetectorWindow.xaml
    /// </summary>
    public partial class NICDetectorWindow : Window
    {
        private ObservableCollection<NICInfo> mNICs;
        private System.Threading.Timer mNICUpdateTimer;
        private string mostActiveInterfaceName;

        public NICDetectorWindow()
        {
            InitializeComponent();
            mNICs = new ObservableCollection<NICInfo>();

        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if (NetworkInterface.GetIsNetworkAvailable())
            {
                IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();
                NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();

                foreach (NetworkInterface adapter in nics)
                {
                    if (!string.IsNullOrEmpty(adapter.Name))
                    {
                        IPInterfaceProperties properties = adapter.GetIPProperties();

                        var hasIPv4Addresses = from p in properties.UnicastAddresses
                                               where p.Address.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(p.Address)
                                               select p.Address;

                        if (adapter.Supports(NetworkInterfaceComponent.IPv4) == true && hasIPv4Addresses.Count() > 0)
                        {
                            NICInfo n = new NICInfo();
                            n.AdapterName = adapter.Name;
                            n.IPAddress = hasIPv4Addresses.First();
                            n.ConnectionName = adapter.Description;
                            n.BytesReceived = "0";
                            n.StartBytesReceived = adapter.GetIPv4Statistics().BytesReceived;
                            n.Speed = FormatSpeed(adapter.Speed, "bps");
                            mNICs.Add(n);
                        }
                    }
                }

                listViewNIC.ItemsSource = mNICs;
                TimerCallback timerDelegate = new TimerCallback(OnNICUpdate);

                mNICUpdateTimer = new System.Threading.Timer(timerDelegate, null, 500, 500);
            }
            else
            {
                MessageBox.Show("No network connections are currently available. Please check your cable connections and system settings.", "No Connections Available", MessageBoxButton.OK, MessageBoxImage.Error);
                this.Close();
            }
        }

        public void OnNICUpdate(Object stateInfo)
        {
            if (NetworkInterface.GetIsNetworkAvailable())
            {
                // Determine maximum interface speed
                long currentBytes, maxBytes = 0;
                NetworkInterface maxInterface = null;

                foreach (NetworkInterface iface in NetworkInterface.GetAllNetworkInterfaces())
                {
                    if (iface.OperationalStatus != OperationalStatus.Up) continue;


                    var curNICInfo = from p in mNICs
                                        where p.AdapterName == iface.Name
                                        select p;
                    if (curNICInfo.Count() > 0)
                    {
                        int curIndex = mNICs.IndexOf(curNICInfo.First());
                        mNICs[curIndex].BytesReceived = string.Format("{0:N0}", iface.GetIPv4Statistics().BytesReceived - mNICs[curIndex].StartBytesReceived);

                        currentBytes = iface.GetIPv4Statistics().BytesReceived + iface.GetIPv4Statistics().BytesSent;
                        if (currentBytes > maxBytes)
                        {
                            maxInterface = iface;
                            maxBytes = currentBytes;
                        }
                    }
                }

                if (maxInterface != null)
                {
                    var mostActive = from p in mNICs
                                       where p.AdapterName == maxInterface.Name
                                       select p;
                    if (mostActive.Count() > 0)
                    {
                        int mostActiveIndex = mNICs.IndexOf(mostActive.First());
                        mNICs[mostActiveIndex].IsMostActive = true;
                    }

                    if (maxInterface.Name != mostActiveInterfaceName)
                    {
                        var oldMostActive = from p in mNICs
                               where p.AdapterName == mostActiveInterfaceName
                               select p;
                        if (oldMostActive.Count() > 0)
                        {
                            mNICs[mNICs.IndexOf(oldMostActive.First())].IsMostActive = false;
                        }

                        mostActiveInterfaceName = maxInterface.Name;
                    }
                    return;
                }
            }
        }

        private void editSelectionButton_Click(object sender, RoutedEventArgs e)
        {
            NICInfo.BindMostActiveAdapter = false;
            EnumAndEnableRadioButtons(listViewNIC);
        }

        private static void EnumAndEnableRadioButtons(Visual myVisual)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
            {
                // Retrieve child visual at specified index value.
                Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i);

                // Do processing of the child visual object.
                if (childVisual is RadioButton)
                {
                    (childVisual as RadioButton).IsEnabled = true;
                }

                // Enumerate children of the child visual object.
                EnumAndEnableRadioButtons(childVisual);
            }
        }

        private void listViewNIC_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Prevent selections in the listview
            listViewNIC.SelectedItem = null;
        }

        private static char[] prefixes = { ' ', 'K', 'M', 'G' };

        /// <summary>
        /// Converts number of bits to a power of 1000 measurement
        /// </summary>
        /// <param name="val">Value to format, in power of 1000 (such as bits per second)</param>
        private static string FormatSpeed(double val, string unit)
        {
            int places = ((int)Math.Log10(val) / 3) * 3;

            char prefix = prefixes[places / 3];
            double amt = val / Math.Pow(10, places);

            return string.Format("{0:0.0}{1}{2}", amt, prefix, unit);
        }
}


    public class NICInfo : INotifyPropertyChanged
    {
        private string mAdapterName;
        private IPAddress mIPAddress;
        private string mSpeed;
        private string mConnectionName;
        private string mBytesReceived;
        private bool mIsMostActive;
        private long mStartBytesReceived;
        private static bool mBindMostActiveAdapter;

        public NICInfo()
        {
            mBindMostActiveAdapter = true;
        }

        public static bool BindMostActiveAdapter
        {
            get { return mBindMostActiveAdapter; }
            set { mBindMostActiveAdapter = value; }
        }

        public string AdapterName
        {
            get { return mAdapterName; }
            set { mAdapterName = value; }
        }

        public IPAddress IPAddress
        {
            get { return mIPAddress; }
            set { mIPAddress = value; }
        }

        public string Speed
        {
            get { return mSpeed; }
            set { mSpeed = value; }
        }

        public string ConnectionName
        {
            get { return mConnectionName; }
            set { mConnectionName = value; }
        }

        public string BytesReceived
        {
            get { return mBytesReceived; }
            set
            {
                mBytesReceived = value;
                OnPropertyChanged("BytesReceived");
            }
        }

        public bool IsMostActive
        {
            get { return mIsMostActive; }
            set
            {
                mIsMostActive = value;
                if (mBindMostActiveAdapter)
                {
                    OnPropertyChanged("IsMostActive");
                }
            }
        }

        public long StartBytesReceived
        {
            get { return mStartBytesReceived; }
            set { mStartBytesReceived = value; }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}
